"""Config options for the 'report' app"""

import logging
import os
import shutil
import warnings
from pathlib import Path

from django.apps import AppConfig
from django.conf import settings
from django.core.exceptions import AppRegistryNotReady
from django.db.utils import IntegrityError, OperationalError, ProgrammingError

logger = logging.getLogger("inventree")


class ReportConfig(AppConfig):
    """Configuration class for the 'report' app"""
    name = 'report'

    def ready(self):
        """This function is called whenever the report app is loaded."""
        from InvenTree.ready import (canAppAccessDatabase, isImportingData,
                                     isInMainThread, isPluginRegistryLoaded)

        # skip loading if plugin registry is not loaded or we run in a background thread
        if not isPluginRegistryLoaded() or not isInMainThread():
            return

        # Configure logging for PDF generation (disable "info" messages)
        logging.getLogger('fontTools').setLevel(logging.WARNING)
        logging.getLogger('weasyprint').setLevel(logging.WARNING)

        # Create entries for default report templates
        if canAppAccessDatabase(allow_test=False) and not isImportingData():

            try:
                self.create_default_test_reports()
                self.create_default_build_reports()
                self.create_default_bill_of_materials_reports()
                self.create_default_purchase_order_reports()
                self.create_default_sales_order_reports()
                self.create_default_return_order_reports()
                self.create_default_stock_location_reports()
            except (AppRegistryNotReady, IntegrityError, OperationalError, ProgrammingError):
                # Database might not yet be ready
                warnings.warn('Database was not ready for creating reports', stacklevel=2)

    def create_default_reports(self, model, reports):
        """Copy default report files across to the media directory."""
        # Source directory for report templates
        src_dir = Path(__file__).parent.joinpath(
            'templates',
            'report',
        )

        # Destination directory
        dst_dir = settings.MEDIA_ROOT.joinpath(
            'report',
            'inventree',
            model.getSubdir(),
        )

        if not dst_dir.exists():
            logger.info("Creating missing directory: '%s'", dst_dir)
            dst_dir.mkdir(parents=True, exist_ok=True)

        # Copy each report template across (if required)
        for report in reports:

            # Destination filename
            filename = os.path.join(
                'report',
                'inventree',
                model.getSubdir(),
                report['file'],
            )

            src_file = src_dir.joinpath(report['file'])
            dst_file = settings.MEDIA_ROOT.joinpath(filename)

            if not dst_file.exists():
                logger.info("Copying test report template '%s'", dst_file)
                shutil.copyfile(src_file, dst_file)

            try:
                # Check if a report matching the template already exists
                if model.objects.filter(template=filename).exists():
                    continue

                logger.info("Creating new TestReport for '%s'", report.get('name'))

                model.objects.create(
                    name=report['name'],
                    description=report['description'],
                    template=filename,
                    enabled=True
                )

            except Exception:
                pass

    def create_default_test_reports(self):
        """Create database entries for the default TestReport templates, if they do not already exist."""
        try:
            from .models import TestReport
        except Exception:  # pragma: no cover
            # Database is not ready yet
            return

        # List of test reports to copy across
        reports = [
            {
                'file': 'inventree_test_report.html',
                'name': 'InvenTree Test Report',
                'description': 'Stock item test report',
            },
        ]

        self.create_default_reports(TestReport, reports)

    def create_default_bill_of_materials_reports(self):
        """Create database entries for the default Bill of Material templates (if they do not already exist)"""
        try:
            from .models import BillOfMaterialsReport
        except Exception:  # pragma: no cover
            # Database is not ready yet
            return

        # List of Build reports to copy across
        reports = [
            {
                'file': 'inventree_bill_of_materials_report.html',
                'name': 'Bill of Materials',
                'description': 'Bill of Materials report',
            }
        ]

        self.create_default_reports(BillOfMaterialsReport, reports)

    def create_default_build_reports(self):
        """Create database entries for the default BuildReport templates (if they do not already exist)"""
        try:
            from .models import BuildReport
        except Exception:  # pragma: no cover
            # Database is not ready yet
            return

        # List of Build reports to copy across
        reports = [
            {
                'file': 'inventree_build_order.html',
                'name': 'InvenTree Build Order',
                'description': 'Build Order job sheet',
            }
        ]

        self.create_default_reports(BuildReport, reports)

    def create_default_purchase_order_reports(self):
        """Create database entries for the default SalesOrderReport templates (if they do not already exist)"""
        try:
            from .models import PurchaseOrderReport
        except Exception:  # pragma: no cover
            # Database is not ready yet
            return

        # List of Build reports to copy across
        reports = [
            {
                'file': 'inventree_po_report.html',
                'name': 'InvenTree Purchase Order',
                'description': 'Purchase Order example report',
            }
        ]

        self.create_default_reports(PurchaseOrderReport, reports)

    def create_default_sales_order_reports(self):
        """Create database entries for the default Sales Order report templates (if they do not already exist)"""
        try:
            from .models import SalesOrderReport
        except Exception:  # pragma: no cover
            # Database is not ready yet
            return

        # List of Build reports to copy across
        reports = [
            {
                'file': 'inventree_so_report.html',
                'name': 'InvenTree Sales Order',
                'description': 'Sales Order example report',
            }
        ]

        self.create_default_reports(SalesOrderReport, reports)

    def create_default_return_order_reports(self):
        """Create database entries for the default ReturnOrderReport templates"""
        try:
            from report.models import ReturnOrderReport
        except Exception:  # pragma: no cover
            # Database not yet ready
            return

        # List of templates to copy across
        reports = [
            {
                'file': 'inventree_return_order_report.html',
                'name': 'InvenTree Return Order',
                'description': 'Return Order example report',
            }
        ]

        self.create_default_reports(ReturnOrderReport, reports)

    def create_default_stock_location_reports(self):
        """Create database entries for the default StockLocationReport templates"""
        try:
            from report.models import StockLocationReport
        except Exception:  # pragma: no cover
            # Database not yet ready
            return

        # List of templates to copy across
        reports = [
            {
                'file': 'inventree_slr_report.html',
                'name': 'InvenTree Stock Location',
                'description': 'Stock Location example report',
            }
        ]

        self.create_default_reports(StockLocationReport, reports)
